package com.yc.book.servlet;

import com.google.gson.Gson;
import com.yc.book.biz.BizException;
import com.yc.book.vo.Result;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/*
    *封装基础Servlet
    *
    * BookServlet extends BaseServlet
    * 定义统一的地址
    * 查询图书：book/query
    * 新增图书：book/add
    * 修改图书：book/mod
    * 删除图书：book/del
    * 将相关的业务方法定义在一个Servlet中
    * 一个Servlet可以处理多个请求，可以减少代码量
    * BaseServlet还可以将一些通用的操作封装起来，例如
    * 字符集设置，响应内容的设置，自动将结果转换为json
 */
public class BaseServlet  extends HttpServlet {

    protected Gson gson = new Gson();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //基本流程
        //1.统一设置
        //设置字符集
        req.setCharacterEncoding("utf-8");
        resp.setCharacterEncoding("utf-8");
        //设置响应内容的类型
        resp.setContentType("application/json;charset=utf-8");
        //2.获取地址，解析方法名
        String requestURI = req.getRequestURI();
        String methodName = requestURI.substring(requestURI.lastIndexOf("/")+1);

        //获取对象方法 业务方法必须是public修饰
        //并且参数必须是HttpServletRequest和HttpServletResponse
        try {
            Method method = this.getClass().getMethod(methodName,
                    HttpServletRequest.class,HttpServletResponse.class);
            //3.通过反射执行方法
            Object ret = method.invoke(this,req,resp);
            //4.获取方法返回结果，转为json
            gson.toJson(ret,resp.getWriter());
        } catch (NoSuchMethodException | IllegalAccessException e) {
            e.printStackTrace();
            Result result = new Result(0,"业务繁忙",null);
            gson.toJson(result,resp.getWriter());
            //向管理员发送邮件或短信，通知异常，记录现场日志
        } catch (InvocationTargetException e ) {
            //InvocationTargetException 是一个运行时异常，它的getCause（）方法可以获取异常的原因
            //使用反射的方式执行业务方法，如果业务员方法出现异常，会被包装成InvocationTargetException
            Throwable cause = e.getCause();
            Result result = null;
            if (cause instanceof BizException){
                result = new Result(0,cause.getMessage(),null);
            }else {
                e.printStackTrace();
                result = new Result(0,"业务繁忙，请联系客服",null);
            }
            gson.toJson(result,resp.getWriter());
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
